package com.iwat.aspect;

import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.iwat.annotation.Dict;
import com.iwat.pojo.User;
import com.iwat.service.UserService;
import com.iwat.vo.DictVo;
import com.iwat.vo.ListDictVo;
import com.iwat.vo.Result;
import lombok.Data;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @Author wangweiqiang
 * @Classname DictAspect
 * @Date 2023/9/22 10:51
 * @Description controller环绕通知
 */
@Data
@Aspect
@Component
public class DictAspect {
    private UserService userService;

    @Autowired
    public DictAspect(UserService userService) {
        this.userService = userService;
    }


    @Pointcut("execution(* com.iwat.controller.*.*(..))")
    public void pointCut() {
    }

    public static void main(String[] args) throws JsonProcessingException {
        User u = new User();
        u.setId(1);
        u.setUserName("zs");
        u.setNote("sb");

        ObjectMapper mapper = new ObjectMapper();
        String s = mapper.writeValueAsString(u);
        System.out.println(s);
    }

    @Around("pointCut()")
    public Object logAfterReturning(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = joinPoint.proceed();
        //将新封装的属性放入到返回结果中
        Result ultimateResult = new Result();
        //判断返回结果是否是Result类型
        if (result instanceof Result) {
            Result r = (Result) result;
            Object data = r.getResult();
            if (data instanceof IPage) {
                Page page = (Page) data;
                //翻译分页对象中的数据
                List<?> records = page.getRecords();
                List<JSONObject> resJson = new ArrayList<>();
                for (Object record : records) {
                    JSONObject object = translateObject(record);
                    resJson.add(object);
                }
                page.setRecords(resJson);
            } else if (data instanceof DictVo) {
                Object obj = ((DictVo) data).getObj();
                JSONObject resJson = translateObject(obj);
                //将包装类（DictVO、ListDictVo）的这一层，从result中去掉
                BeanUtils.copyProperties(result, ultimateResult);
                ultimateResult.setResult(resJson);
                result = ultimateResult;
            } else if (data instanceof ListDictVo) {
                List list = ((ListDictVo) data).getList();
                List<JSONObject> resJson = new ArrayList<>();
                for (Object obj : list) {
                    JSONObject object = translateObject(obj);
                    resJson.add(object);
                }
                BeanUtils.copyProperties(result, ultimateResult);
                ultimateResult.setResult(resJson);
                result = ultimateResult;
            }
        }
        return result;
    }

    /**
     * 讲一个对象中携带@Dict注解的属性转换成字典值，并添加到原对象中
     *
     * @param obj
     * @return
     * @throws JsonProcessingException
     * @throws JSONException
     */
    private JSONObject translateObject(Object obj) throws JsonProcessingException, JSONException {
        Field[] fields = getAllFields(obj);
        //对象转json
        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        String json = mapper.writeValueAsString(obj);
        JSONObject resJson = JSONUtil.parseObj(json,false);

        for (Field field : fields) {
            Annotation[] annotations = field.getAnnotations();
            Annotation dict = Arrays.stream(annotations).filter(e -> e instanceof Dict).findFirst().orElse(null);
            if (dict == null) {
                continue;
            }
            String key = String.valueOf(resJson.get(field.getName()));
            //获取翻译值
            String value = translateField(key, (Dict) dict);
            resJson.put(field.getName().concat("_dictTxt"), value);
        }
        return resJson;
    }

    /**
     * @param key  当前遍历的属性的值
     * @param d 字典注解
     * @return
     * @throws JSONException
     */
    private String translateField(String key, Dict d) throws JSONException {
        String dictCode = d.dictCode();
        String dictTable = d.dictTable();
        String dictText = d.dictText();
        String value = "";
        if (StringUtils.isNotEmpty(dictCode) && StringUtils.isNotEmpty(dictTable) && StringUtils.isNotEmpty(dictText)) {
            //todo select from other table with optimize by cache
            value = userService.queryTranslationForeign(dictCode, dictText, dictTable, key);
        } else if (StringUtils.isNotEmpty(dictCode) && (StringUtils.isEmpty(dictTable) || StringUtils.isEmpty(dictText))) {
            value = userService.queryTranslation(dictCode, key);
        }
        return value;
    }

    /**
     * 获取一个类所有的属性，包括父类
     *
     * @param obj
     * @return
     */
    private Field[] getAllFields(Object obj) {
        Class<?> cla = null;
        if (obj != null) {
            cla = obj.getClass();
        }
        List<Field> fieldList = new ArrayList<>();

        while (cla != null) {
            fieldList.addAll(Arrays.asList(cla.getDeclaredFields()));
            cla = cla.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        return fields;
    }
}





















